package com.mz361.component.fileUpload;

import com.mz361.common.exception.ResultException;
import com.mz361.common.utils.SpringContextUtil;
import com.mz361.common.utils.ToolUtil;
import com.mz361.component.fileUpload.config.properties.UploadProjectProperties;
import com.mz361.component.fileUpload.enums.UploadResultEnum;
import com.mz361.modules.system.domain.Upload;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.region.Region;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 文件上传处理工具
 *
 * @author niceale * @date 2023/11/4
 */
public class FileUpload {
    private static final String SecretID = "AKID87tRWbTC5lETZTEpJaeU5SbWAaljSxIQ";
    private static final String SecretKey = "qZ5NZcU8ctwlMpA9wVxDLIH71sgPwRsC";
    private static final String REGION = "ap-beijing";
    private static final String BUCKET_NAME = "img-1327002262";
    // 定义一个静态的映射，用于存储文件扩展名和对应的 Content-Type
    private static final Map<String, String> CONTENT_TYPE_MAP = new HashMap<>();

    static {
        CONTENT_TYPE_MAP.put("jpg", "image/jpeg");
        CONTENT_TYPE_MAP.put("jpeg", "image/jpeg");
        CONTENT_TYPE_MAP.put("png", "image/png");
        CONTENT_TYPE_MAP.put("gif", "image/gif");
        CONTENT_TYPE_MAP.put("pdf", "application/pdf");
        CONTENT_TYPE_MAP.put("doc", "application/msword");
        CONTENT_TYPE_MAP.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        CONTENT_TYPE_MAP.put("xls", "application/vnd.ms-excel");
        CONTENT_TYPE_MAP.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        CONTENT_TYPE_MAP.put("ppt", "application/vnd.ms-powerpoint");
        CONTENT_TYPE_MAP.put("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
        CONTENT_TYPE_MAP.put("txt", "text/plain");
        // 可以根据需要添加更多的文件类型映射
    }

    /**
     * 创建一个Upload实体对象
     *
     * @param multipartFile MultipartFile对象
     * @param modulePath    文件模块路径
     */
    public static Upload getFile(MultipartFile multipartFile, String modulePath) {
        if (multipartFile.getSize() == 0) {
            throw new ResultException(UploadResultEnum.NO_FILE_NULL);
        }
        Upload upload = new Upload();
        upload.setMime(multipartFile.getContentType());
        upload.setSize(multipartFile.getSize());
        upload.setName(FileUpload.genFileName(multipartFile.getOriginalFilename()));
        upload.setPath(getPathPattern() + modulePath + FileUpload.genDateMkdir("yyyyMMdd") + upload.getName());
        return upload;
    }

    /**
     * 判断文件是否为支持的格式
     *
     * @param multipartFile MultipartFile对象
     * @param types         支持的文件类型数组
     */
    public static boolean isContentType(MultipartFile multipartFile, String[] types) {
        List<String> typeList = Arrays.asList(types);
        return typeList.contains(multipartFile.getContentType());
    }

    /**
     * 获取文件上传保存路径
     */
    public static String getUploadPath() {
        UploadProjectProperties properties = SpringContextUtil.getBean(UploadProjectProperties.class);
        return properties.getFilePath();
    }

    /**
     * 获取文件上传目录的静态资源路径
     */
    public static String getPathPattern() {
        UploadProjectProperties properties = SpringContextUtil.getBean(UploadProjectProperties.class);
        return properties.getStaticPath().replace("/**", "");
    }

    /**
     * 生成随机且唯一的文件名
     */
    public static String genFileName(String originalFilename) {
        String fileSuffix = ToolUtil.getFileSuffix(originalFilename);
        return UUID.randomUUID().toString().replace("-", "") + fileSuffix;
    }

    /**
     * 生成指定格式的目录名称(日期格式)
     */
    public static String genDateMkdir(String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return "/" + sdf.format(new Date()) + "/";
    }

    /**
     * 保存图片及获取文件MD5值和SHA1值
     *
     * @param multipartFile MultipartFile对象
     * @param upload        Upload
     */
    public static void transferTo(MultipartFile multipartFile, Upload upload) throws IOException, NoSuchAlgorithmException {
        byte[] fileBytes = multipartFile.getBytes();
        System.out.println("multipartFile "+fileBytes.length);

        // 获取文件的MD5和SHA1值
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        MessageDigest sha1 = MessageDigest.getInstance("SHA1");
        md5.update(fileBytes);
        sha1.update(fileBytes);
        BigInteger md5Bi = new BigInteger(1, md5.digest());
        BigInteger sha1Bi = new BigInteger(1, sha1.digest());
        upload.setMd5(md5Bi.toString(16));
        upload.setSha1(sha1Bi.toString(16));
        // 上传文件到腾讯云 COS
        COSCredentials cred = new BasicCOSCredentials(SecretID, SecretKey);
        ClientConfig clientConfig = new ClientConfig(new Region(REGION));
        COSClient cosClient = new COSClient(cred, clientConfig);
        String fileExtension = getFileExtension(upload.getPath());
        ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes);
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setHeader("Content-Type", CONTENT_TYPE_MAP.getOrDefault(fileExtension,"application/octet-stream"));
        objectMetadata.setHeader("Content-Disposition", "inline");

        PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET_NAME, upload.getPath(), inputStream, objectMetadata);
        cosClient.putObject(putObjectRequest);
        cosClient.shutdown();
        System.out.println("file uploaded successfully："+upload.getPath());
    }

    /**
     * 获取文件的SHA1值
     */
    public static String getFileSha1(MultipartFile multipartFile) {
        if (multipartFile.getSize() == 0) {
            throw new ResultException(UploadResultEnum.NO_FILE_NULL);
        }
        byte[] buffer = new byte[4096];
        try (InputStream fis = multipartFile.getInputStream()) {
            MessageDigest sha1 = MessageDigest.getInstance("SHA1");
            int len = 0;
            while ((len = fis.read(buffer)) != -1) {
                sha1.update(buffer, 0, len);
            }
            BigInteger sha1Bi = new BigInteger(1, sha1.digest());
            return sha1Bi.toString(16);
        } catch (IOException | NoSuchAlgorithmException e) {
            return null;
        }
    }

    // 获取文件扩展名的方法
    private static String getFileExtension(String filePath) {
        int lastIndex = filePath.lastIndexOf('.');
        if (lastIndex != -1) {
            return filePath.substring(lastIndex + 1).toLowerCase();
        }
        return "";
    }


}
